package com.darco.darcoapp;

import com.darco.darcoapp.interfaces.IGeoLocatingActivity;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;

import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.provider.Settings;
import android.widget.Toast;
import eneter.messaging.endpoints.typedmessages.TypedResponseReceivedEventArgs;
import DARCOShared.requests.GetCardJourneyRequest;
import DARCOShared.requests.GetPositionsOfNearbyUsersRequest;
import DARCOShared.requests.RequestBase;
import DARCOShared.requests.RequestType;
import DARCOShared.responses.GetCardJourneyResponse;
import DARCOShared.responses.GetPositionsOfNearbyUsersResponse;
import DARCOShared.responses.ResponseBase;
import DARCOShared.responses.ResponseType;
import DARCOShared.responses.ResponseWrapper;
import DARCOShared.utils.Trade;
import static DARCOShared.utils.Constants.*;

public class CardJourneyActivity extends MessagingActivity implements IGeoLocatingActivity{
	private int MODE;

	private MessagingManager mm;
	private GoogleMap myGoogleMap;
	private GeolocationHelper myGeolocator;
	private String requestedCardSN;
	private String requestedCardUID;
	private String userToFind;
	private ContentValues account;
	GetPositionsOfNearbyUsersRequest myRequest;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
		boolean gmaps = true;
		try{
		     ApplicationInfo info = getPackageManager().getApplicationInfo("com.google.android.apps.maps", 0 );
		    } catch( PackageManager.NameNotFoundException e ){
		    	gmaps = false;
		}
		if(result != ConnectionResult.SUCCESS || !gmaps){
			showFailedAlert("Google maps or the Google Play Services API is not installed on your phone. Please install them and try again.");
			return;
		}

		setContentView(R.layout.activity_card_journey);
		myGoogleMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapFragmentCardJourney)).getMap();
		myGeolocator = new GeolocationHelper(this);

		Bundle extras = getIntent().getExtras();

		MODE = (int)getIntent().getExtras().getInt("mode");
		account = (ContentValues)getIntent().getExtras().get("account");

		switch(MODE){
		case MODE_CARD_JOURNEY : 
		{
			requestedCardSN = extras.getString("cardSN");
			requestedCardUID = extras.getString("cardUID");
			GetCardJourneyRequest req = new GetCardJourneyRequest(requestedCardSN, requestedCardUID);
			onPerformRequest(req);
			break;
		}
		case MODE_LOCATE_SPECIFIC_USER :
		{
			userToFind = extras.getString("userToFind");
			myRequest = new GetPositionsOfNearbyUsersRequest(account.getAsString(ACCOUNT_EMAIL), account.getAsString(ACCOUNT_PASSWORD), MODE);
			myRequest.requestedEmail = userToFind;
			onPerformRequest(myRequest);
			break;
		}
		case MODE_LOCATE_USERS_NEAR_ME :
		{
			myRequest = new GetPositionsOfNearbyUsersRequest(account.getAsString(ACCOUNT_EMAIL), account.getAsString(ACCOUNT_PASSWORD), MODE);
			showLoadingDialog("Geolocating", "Locating your current position, please wait...");
			if(!myGeolocator.startGeoLocating())
				buildAlertMessageNoGps();
			break;
		}
		case MODE_LOCATE_CARD_OWNERS_NEAR_ME :
		{
			requestedCardSN = extras.getString("cardSN");
			myRequest = new GetPositionsOfNearbyUsersRequest(account.getAsString(ACCOUNT_EMAIL), account.getAsString(ACCOUNT_PASSWORD), MODE);
			myRequest.requestedCardSN = requestedCardSN;
			showLoadingDialog("Geolocating", "Locating your current position, please wait...");
			if(!myGeolocator.startGeoLocating())
				buildAlertMessageNoGps();
			break;
		}

		}


	}


	@Override
	void onResponseReceived(Object sender, TypedResponseReceivedEventArgs<ResponseWrapper> e) {
		hideLoadingDialog();
		ResponseBase resp =e.getResponseMessage().getResponse(); 
		if(resp.getResponseType() == ResponseType.GetCardJourney){
			GetCardJourneyResponse r = (GetCardJourneyResponse)resp;
			if(r.hasError){
				Toast.makeText(this, "Error: " + r.errorMessage, Toast.LENGTH_LONG).show();
				return;
			}
			else{
				drawTradesOnMap(r);
			}
		}

		if(resp.getResponseType() == ResponseType.GetNearestOwners){
			GetPositionsOfNearbyUsersResponse r = (GetPositionsOfNearbyUsersResponse)resp;
			if(r.hasError)
				showFailedAlert(r.errorMessage);
			else
				drawPositionsOnMap(r);
		}
	}

	private void drawPositionsOnMap(GetPositionsOfNearbyUsersResponse r) {
		float minLat = myGeolocator.getLatitude();
		float maxLat = myGeolocator.getLatitude();
		float minLon = myGeolocator.getLongitude();
		float maxLon = myGeolocator.getLongitude();
		
		for (int i = 0; i < r.latitudes.size(); i++) {
			float lat = r.latitudes.get(i);
			float lon = r.longitudes.get(i);
			
			if(lat < minLat)
				minLat = lat;
			if(lat > maxLat)
				maxLat = lat;
			if(lon < minLon)
				minLon = lon;
			if(lon > maxLon)
				maxLon = lon;
			
			Marker m = myGoogleMap.addMarker(new MarkerOptions()
			.position(new LatLng(lat, lon))
			.title(r.emails.get(i))
			.snippet("Last seen here"));


		}

		if(MODE != MODE_LOCATE_SPECIFIC_USER){
			Marker m = myGoogleMap.addMarker(new MarkerOptions()
			.position(new LatLng(myGeolocator.getLatitude(), myGeolocator.getLongitude()))
			.title("Your current position"));
			m.showInfoWindow();
		}
		
		myGoogleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(new LatLngBounds(new LatLng(minLat, minLon), new LatLng(maxLat, maxLon)), 15));
		
	}


	private void drawTradesOnMap(GetCardJourneyResponse r) {
		PolylineOptions lineopt = new PolylineOptions();
		for (int i = 0; i < r.trades.size(); i++) {
			Trade t = r.trades.get(i);
			Marker m = myGoogleMap.addMarker(new MarkerOptions()
			.position(new LatLng(t.latitude, t.longitude))
			.title(t.oldOwner + " --> " + t.newOwner)
			.snippet(t.date));

			lineopt.add(m.getPosition());

			if(i == 0){
				m.showInfoWindow();
				myGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(m.getPosition()));
				myGoogleMap.moveCamera(CameraUpdateFactory.zoomTo(10));
			}
		}
		lineopt.color(Color.RED);
		myGoogleMap.addPolyline(lineopt);
	}


	void onPerformRequest(RequestBase req){
		if(req.getRequestType() == RequestType.GetCardJourney)
			showLoadingDialog("Contacting server", "Asking server for the history of th card, please wait...");
		if(req.getRequestType() == RequestType.GetNearestOwners)
			showLoadingDialog("Contacting server", "Asking server for information, please wait...");

		if(mm != null)
			mm.CloseConnection();

		mm = new MessagingManager();
		boolean connected = mm.ConnectToServer(this); 
		boolean sent = mm.SendRequest(req, this); 
		if(!connected || !sent)
			showFailedAlert("Failed to communicate with the server: network or firewall problem.");
	}


	@Override
	public void onLocationObtained() {
		hideLoadingDialog();
		if(MODE != MODE_CARD_JOURNEY){
			myRequest.senderLatitude = myGeolocator.getLatitude();
			myRequest.senderLongitude = myGeolocator.getLongitude();
			onPerformRequest(myRequest);
		}

	}

	private void showSuccessAlert(){
		hideLoadingDialog();
		AlertDialog dialogBox = new AlertDialog.Builder(this).create();
		dialogBox.setTitle("Location update succesfull");
		dialogBox.setMessage("Your current position has been pinpointed and updated on the server.");
		dialogBox.setButton("Ok",  new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				finish();
			}
		});
		dialogBox.show();
	}

	private void showFailedAlert(String message){
		hideLoadingDialog();
		AlertDialog dialogBox = new AlertDialog.Builder(this).create();
		dialogBox.setTitle("Location update failed");
		dialogBox.setMessage(message);
		dialogBox.setButton("Ok",  new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				finish();
			}
		});
		dialogBox.show();
	}
	
	private void buildAlertMessageNoGps() {
	    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
	    builder.setMessage("Yout GPS seems to be disabled, do you want to enable it?")
	           .setCancelable(false)
	           .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
	               public void onClick(final DialogInterface dialog, final int id) {
	                   startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
	               }
	           })
	           .setNegativeButton("No", new DialogInterface.OnClickListener() {
	               public void onClick(final DialogInterface dialog, final int id) {
	                    dialog.cancel();
	                    finish();
	               }
	           });
	    final AlertDialog alert = builder.create();
	    alert.show();
	}
}
